package com.sxf.auth.captcha;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.NumberFormat;
import java.util.*;

/**
 * @author: SSLi
 * @description 验证码图片成
 * @date: 2020/4/15 9:54
 */
public class VerifyImageHelper {

    private static final Logger log = LoggerFactory.getLogger(VerifyImageHelper.class);

    /** 源文件宽度 */
    private static int ORI_WIDTH = 546;
    /** 源文件高度 */
    private static int ORI_HEIGHT = 364;
    /** 抠图坐标x */
    private  int X;
    /** 抠图坐标y */
    private  int Y;
    /** 模板图宽度 */
    private static int WIDTH;
    /** 模板图高度 */
    private static int HEIGHT;
    /** X位置移动百分比 */
//    private  float xPercent;
    /** Y位置移动百分比 */
    private  float yPercent;



    public static Map<String, Object> generateImage(File templateFile, File targetFile,File underFile) throws Exception {
        VerifyImageHelper verifyImageHelper = new VerifyImageHelper();
        return verifyImageHelper.pictureTemplatesCut(templateFile,targetFile,underFile,"png","png");
    }


    /**
     * 根据模板切图
     *
     * @param templateFile 模板图片
     * @param targetFile 目标图片
     * @param templateType 模板图片类型
     * @param targetType 目标图片图片类型
     * @return 图片信息
     * @throws Exception 异常
     */
    public Map<String, Object> pictureTemplatesCut(File templateFile, File targetFile,File underFile, String templateType, String targetType) throws Exception {
        Map<String, Object> pictureMap = null;
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        // 源文件流
        InputStream targetInput = new FileInputStream(targetFile);
        try {
            pictureMap = new HashMap<>(16);
            // 文件类型
            if (StringUtils.isEmpty(templateType) || StringUtils.isEmpty(targetType)) {
                throw new RuntimeException("file type is empty");
            }
            // 模板图
            BufferedImage imageTemplate = ImageIO.read(templateFile);
            WIDTH = imageTemplate.getWidth();
            HEIGHT = imageTemplate.getHeight();
            // 模板图
            BufferedImage imageTarget = ImageIO.read(targetFile);
            ORI_WIDTH = imageTarget.getWidth();
            ORI_HEIGHT = imageTarget.getHeight();

            generateCutoutCoordinates();
            // 最终图像
            BufferedImage newImage = new BufferedImage(WIDTH, HEIGHT, imageTemplate.getType());
            Graphics2D graphics = newImage.createGraphics();
            graphics.setBackground(Color.white);

            int bold = 5;
            // 获取感兴趣的目标区域
            BufferedImage targetImageNoDeal = getTargetArea(WIDTH, HEIGHT, targetInput, templateType);
            // 根据模板图片抠图
            dealCutPictureByTemplate(targetImageNoDeal, imageTemplate, newImage);
            // 设置“抗锯齿”的属性
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            graphics.setStroke(new BasicStroke(bold, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
            graphics.drawImage(newImage, 0, 0, null);

            graphics.dispose();

            ImageIO.write(newImage, templateType, os);

            byte[] newImages = os.toByteArray();
            // 源图生成遮罩
            byte[] oriCopyImages = dealOriPictureByTemplate(imageTarget, imageTemplate,underFile, X, Y);
            pictureMap.put("backImage", new String(Base64.getEncoder().encode(oriCopyImages)) );
            pictureMap.put("cutImage",new String(Base64.getEncoder().encode(newImages)));
            pictureMap.put("X",X);
            pictureMap.put("Y",Y);
            pictureMap.put("yPercent",yPercent);
        }finally {
            os.close();
            targetInput.close();
        }
        return pictureMap;
    }

    /**
     * 抠图后原图生成
     *
     * @param oriImage 原图
     * @param templateImage 模板图
     * @param x 抠图坐标
     * @param y 抠图坐标
     * @throws Exception 异常
     */
    private byte[] dealOriPictureByTemplate(BufferedImage oriImage, BufferedImage templateImage,File underFile, int x,
                                                   int y) throws Exception {
        // 源文件备份图像矩阵 支持alpha通道的rgb图像
        BufferedImage oriCopyImage = new BufferedImage(oriImage.getWidth(), oriImage.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
        // 源文件图像矩阵
        int[][] oriImageData = getData(oriImage);
        // 模板图像矩阵
//        int[][] templateImageData = getData(templateImage);

        //copy 源图做不透明处理
        for (int i = 0; i < oriImageData.length; i++) {
            for (int j = 0; j < oriImageData[0].length; j++) {
                int rgb = oriImage.getRGB(i, j);
                if (rgb<0){
                    int r = (0xff & rgb);
                    int g = (0xff & (rgb >> 8));
                    int b = (0xff & (rgb >> 16));
                    //无透明处理
                    rgb = r + (g << 8) + (b << 16) + (255 << 24);
                    oriCopyImage.setRGB(i, j, rgb);
                }
            }
        }
        BufferedImage imageUnder = ImageIO.read(underFile);
        Graphics2D graphics = oriCopyImage.createGraphics();
        graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1F));
        // 绘制
        graphics.drawImage(imageUnder, x, y,HEIGHT, WIDTH,null);
        graphics.dispose();

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(oriCopyImage, "png", os);

        return os.toByteArray();
    }


    /**
     * 根据模板图片抠图
     *
     * @param oriImage 原图
     * @param templateImage 模板图
     */

    private void dealCutPictureByTemplate(BufferedImage oriImage, BufferedImage templateImage,
                                                 BufferedImage targetImage) {
        // 源文件图像矩阵
        int[][] oriImageData = getData(oriImage);
        // 模板图像矩阵
        int[][] templateImageData = getData(templateImage);
        // 模板图像宽度
        try {
            for (int i = 0; i < templateImageData.length; i++) {
                // 模板图片高度
                for (int j = 0; j < templateImageData[0].length; j++) {
                    // 如果模板图像当前像素点不是白色 copy源文件信息到目标图片中
                    int rgb = templateImageData[i][j];
                    if (rgb < 0) {
                        targetImage.setRGB(i, j, oriImageData[i][j]);
                    }
                }
            }
        } catch (Exception e) {
            log.error("X:"+X+ "||Y:"+Y,e);
        }
    }


    /**
     * 获取目标区域
     *
     * @param targetWidth  切图后目标宽度
     * @param targetHeight 切图后目标高度
     * @param ois          源文件输入流
     * @throws Exception 异常
     */
    private BufferedImage getTargetArea(int targetWidth, int targetHeight, InputStream ois,
                                               String fileType) throws Exception {
        Iterator<ImageReader> imageReaderList = ImageIO.getImageReadersByFormatName(fileType);
        ImageReader imageReader = imageReaderList.next();
        // 获取图片流
        ImageInputStream iis = ImageIO.createImageInputStream(ois);
        // 输入源中的图像将只按顺序读取
        imageReader.setInput(iis, true);

        ImageReadParam param = imageReader.getDefaultReadParam();
        Rectangle rec = new Rectangle(X, Y, targetWidth, targetHeight);
        param.setSourceRegion(rec);
        return imageReader.read(0, param);
    }

    /**
     * 生成图像矩阵
     *
     * @param img 图片流
     * @return 二维数组
     */
    private int[][] getData(BufferedImage img) {
        int[][] data = new int[img.getWidth()][img.getHeight()];
        for (int i = 0; i < img.getWidth(); i++) {
            for (int j = 0; j < img.getHeight(); j++) {
                data[i][j] = img.getRGB(i, j);
            }
        }
        return data;
    }

    /**
     * 随机生成抠图坐标
     */
    private void generateCutoutCoordinates() {
        Random random = new Random();
        //左右留20个像素空位
        int widthDifference = ORI_WIDTH - WIDTH - 40;
        int heightDifference = ORI_HEIGHT - HEIGHT - 40;

        if (widthDifference <= 0) {
            X = 5;

        } else {
            X = random.nextInt(widthDifference) + 20;
            /*@herb 解决切图相对位置问题*/
            if (X < WIDTH) {
                X = WIDTH;
            }
        }

        if (heightDifference <= 0) {
            Y = 5;
        } else {
            Y = random.nextInt(heightDifference) + 20;
        }
        NumberFormat numberFormat = NumberFormat.getInstance();
        numberFormat.setMaximumFractionDigits(2);

//        xPercent = Float.parseFloat(numberFormat.format((float) X / (float) ORI_WIDTH));
        yPercent = Float.parseFloat(numberFormat.format((float) Y / (float) ORI_HEIGHT));
    }
}